
package com.agentslab.directorymanager;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;

import aa.core.CyberOrg;
import aa.tool.TupleSpaceException;

/**
 *  This class implements a tuple space that maintains actor tuples. 
 *  An actor tuple consists of the actor name field and property fields.
 * 
 *  <p>
 *  <b>History:</b>
 *  <ul>
 *      <li> February 19, 2004 - version0.0.3
 * 	<ul>
 * 	    <li> do minor modification.
 * 	</ul>
 *      <li> January 26, 2004 - version 0.0.2
 *      <ul>
 *          <li> modify this file a lot.
 *      </ul>
 *      <li> June 3, 2003 - version 0.0.1
 *      <ul>
 *          <li> create this file.
 *      </ul>
 *  </ul>
 * 
 *  @author Myeong-Wuk Jang
 *  @version $Date: 2008/01/01 00:23:57 $ $Revision: 1.1 $
 */

public class CyberOrgTupleSpace 
{
    // ========== Object Variables ========== //
    
    /**
     *  A linked list of actor tuples stored in this tuple space.
     */
    protected LinkedList m_llCyberOrgTuples;
	
	
    // ========== Object Methods ========== //

    /**
     *  Constructs an tuple space.
     */
    public CyberOrgTupleSpace()
    {
    	m_llCyberOrgTuples = new LinkedList();
    }
    
    
    /**
     *  Checks whether the given actor tuple has any null element.
     * 
     *  @param p_ctTuple an actor tuple to be checked.
     * 
     *  @return <code>true</code> if any element of the given CyberOrg tuple is null;
     *          <code>false</code> otherwise.
     */
    private boolean isValidDataTuple(CyberOrgTuple p_ctTuple)
    {
    	//
    	//  check whether either the given actor tuple is null or 
    	//		         the ActorName field is null.
    	//
    	if ( (p_ctTuple == null) ||
    	     (p_ctTuple.getDestination().equals("")) ||
             (p_ctTuple.getFacClassName().equals("")) ||
             (p_ctTuple.getId()==0)) {
    	    return false;
    	}
    	
    	//
    	//  check whether any element field is null.
    	//
//        Object[] objaElements = p_ctTuple.getElements();
//
//	for (int i=0; i<objaElements.length; i++) {
//	    if (objaElements[i] == null) {
//		return false;
//            }
//	}
	
	return true;
    }


    /**
     *  Checks whether element types between the given tuple template and 
     *      the given actor tuple are matched.
     * 
     *  @param p_atTemplate a tuple template to be used for matching with
     *                      actor tuples in this tuple space.
     *  @param p_ctTuple an actor tuple to be stored in this tuple space.
     * 
     *  @return true if element types between the given tuple template and 
     *               the given actor tuple are matched;
     *          false otherwise.
     */
    private boolean areTypeMatched(CyberOrgTuple p_ctTemplate, CyberOrgTuple p_ctTuple)
    {
	Object[] objaTemplateItems = p_ctTemplate.getElements();
	Object[] objaTupleItems    = p_ctTuple.getElements();

	if (objaTemplateItems.length != objaTupleItems.length) {
	    return false;
	}

	for (int i=0; i<objaTupleItems.length; i++) {
	    if (objaTemplateItems[i] != null) {
		if ( (!objaTupleItems[i].getClass().isInstance(objaTemplateItems[i])) ||
		     (!objaTupleItems[i].equals(objaTemplateItems[i])) ) {
		    return false;
		}
	    }
	}

	return true;
    }


    /**
     *  Finds actor tuples in this tuple space matched with the specified tuple template.
     * 
     *  @param p_atTemplate a tuple template to be used for matching with actor tuples
     * 			    in this tuple space.
     *  @param p_bActorName the flag to decide whether ActorName will be checked or not.
     * 
     *  @return actor tuples matched with the specified tuple template.
     * 
     *  @throws TupleSpaceException if the given tuple template is null.
     */
    protected CyberOrgTuple[] getMatchedTupleList(CyberOrgTuple p_ctTemplate, boolean p_bActorName)
	throws TupleSpaceException
    {
    	//
    	//  check whether the given tuple template is null.
    	//
    	if (p_ctTemplate == null) {
            throw new TupleSpaceException("Tuple template shoud not be null");
    	}
    	
    	//
    	//  find actor tuples matched with the specified tuple template.
    	//
	LinkedList llTmp = new LinkedList();

	CyberOrg anTemplate = p_ctTemplate.getCyberOrg();
	Object[] objaTemplateElement = p_ctTemplate.getElements();

        Iterator iterCyberOrgTuples = m_llCyberOrgTuples.iterator();

	while (iterCyberOrgTuples.hasNext()) {
	    CyberOrgTuple ctTuple = (CyberOrgTuple) iterCyberOrgTuples.next();
	    
	    //
	    //  compare ActorName in the template with that in an actor tuple.
	    //
	    CyberOrg  anTuple = ctTuple.getCyberOrg();

	    if (p_bActorName) {
	    	//
	    	//  if ActorName in the template is different from that in an actor tuple,
	    	//  then skip this tuple.
	    	//
	    	if ( (anTemplate != null) &&
	    	     (!anTemplate.equals(anTuple)) ) {
	    	     continue;
	    	}
	    }

	    //
	    //  compare elements in the template with those in an actor tuple.
	    //
	    Object[] objaDataElement = ctTuple.getElements();

            if (objaDataElement.length == objaTemplateElement.length) {
                boolean bFound = true;
 
                for (int i=0; i<objaTemplateElement.length; i++) {
		    if (objaTemplateElement[i] != null) {
			if ( (!objaTemplateElement[i].getClass().isInstance(objaDataElement[i])) ||
			     (!objaTemplateElement[i].equals(objaDataElement[i])) ) {
			    bFound = false;
			    break;
			}
		    }
                }

                if (bFound) {
                    llTmp.add(ctTuple);
                }
            }
        };

//	return (CyberOrgTuple[]) llTmp.toArray();
	CyberOrgTuple ataTmp[] = new CyberOrgTuple[llTmp.size()];
	llTmp.toArray(ataTmp);
	return ataTmp;
    }


    /**
     *  Gets a actor tuple matched with the specified tuple template,
     *     and remove it if <code>bRemoveFlag</code> is true.
     * 
     *  @param p_ctTemplate a tuple template to be used for matching with actor tuples
     * 				in this tuple space.
     *  @param p_bRemoveFlag the flag to remove a tuple after the tuple is retrieved.
     * 
     *  @return an actor tuple matched with the specified tuple template.
     * 
     *  @throws TupleSpaceException if this tuple space cannot find any actor tuple 
     *               that are matched with the specified tuple template.
     */
    private CyberOrgTuple getImpl(CyberOrgTuple p_ctTemplate, boolean p_bRemoveFlag)
	throws TupleSpaceException
    {
	CyberOrgTuple[] ctMatchedTuples = getMatchedTupleList(p_ctTemplate, true);

        if (ctMatchedTuples.length > 0) {
	    Random rnd = new Random();
	    int iIdx = rnd.nextInt(ctMatchedTuples.length);

	    if (p_bRemoveFlag) {
		m_llCyberOrgTuples.remove(ctMatchedTuples[iIdx]);
	    }

            return ctMatchedTuples[iIdx];
        } else {
            throw new TupleSpaceException("Cannot Find Any Tuple");
        }
    }


    /**
     *  Returns all actor tuples matched with the specified tuple template, 
     *      and remove them if <code>bRemoveFlag</code> is true.
     * 
     *  @param p_atTemplate a tuple template to be used for matching with actor tuples
     * 			    in this tuple space.
     *  @param p_bRemoveFlag the flag to remove actor tuples after they are retrieved.
     * 
     *  @return actor tuples matched with the specified tuple template.
     * 
     *  @throws TupleSpaceException 
     *              if this tuple space cannot find any actor tuple.
     */
    private CyberOrgTuple[] getAllImpl(CyberOrgTuple p_ctTemplate, boolean p_bRemoveFlag)
	throws TupleSpaceException
    {
	CyberOrgTuple[] anMatchedTuples = getMatchedTupleList(p_ctTemplate, true);

        if (anMatchedTuples.length > 0) {
	    if (p_bRemoveFlag) {
	    	for (int i=0; i<anMatchedTuples.length; i++) {
		    m_llCyberOrgTuples.remove(anMatchedTuples[i]);
	    	}
	    }

            return (CyberOrgTuple[])anMatchedTuples;
        } else {
            throw new TupleSpaceException("Cannot Find Any Tuple");
        }
    }

    
    /**
     *  Inserts an CyberOrg tuple in this tuple space.
     *
     *  @param p_ctTuple an CyberOrg tuple to be stored in this tuple space.
     * 
     *  @throws TupleSpaceException 
     *              either if the actor tuple is invalid or 
     *                     if the same CyberOrg tuple already exits in this tuple space.
     */
    public void write(CyberOrgTuple p_ctTuple)
	throws TupleSpaceException
    {
	//
	//  check if the CyberOrg tuple is valid.
	//
	if (!isValidDataTuple(p_ctTuple)) {
	    throw new TupleSpaceException("Illegal Paramer - " +
	    		"Each element of an CyberOrg tuple should not be null");
	}
        m_llCyberOrgTuples.add(p_ctTuple);
	//
	//  check whether the same tuple already exists.
	//
//	CyberOrgTuple[] anMatchedTuples = getMatchedTupleList(p_ctTuple, true);
//
//	if (anMatchedTuples.length == 0) {
//	    m_llCyberOrgTuples.add(p_ctTuple);
//	} else {
//	    throw new TupleSpaceException("This tuple is already registered");
//	}
    }


    /**
     *  Reads an CyberOrg tuple matched with the specified tuple template.
     * 
     *  @param p_ctTemplate a tuple template to be used for matching with
     *                      CyberOrg tuples in this tuple space.
     * 
     *  @return an CyberOrgTuple tuple matched with the specified tuple template.
     * 
     *  @throws TupleSpaceException 
     *              if this tuple space cannot find any CyberOrg tuple
     *              that are matched with the specified tuple template.
     */
    public final CyberOrgTuple read(CyberOrgTuple p_ctTemplate)
	throws TupleSpaceException
    {
	return(getImpl(p_ctTemplate, false));
    } 


    /**
     *  Reads all CyberOrg tuples matched with the specified tuple template.
     * 
     *  @param p_ctTemplate a tuple template to be used for matching with
     *                      CyberOrg tuples in this tuple space.
     * 
     *  @return all CyberOrg tuples matched with the specified tuple template.
     * 
     *  @throws TupleSpaceException 
     *              if this tuple space cannot find any CyberOrg tuple
     *              that are matched with the specified tuple template.
     */
    public final CyberOrgTuple[] readAll(CyberOrgTuple p_ctTemplate)
	throws TupleSpaceException
    {
    	return(getAllImpl(p_ctTemplate, false));
    }
    

    /**
     *  Reads an CyberOrg tuple matched with the specified tuple template,
     *      and then removes it.
     * 
     *  @param p_ctTemplate a tuple template to be used for matching with
     *                      CyberOrg tuples in this tuple space.
     * 
     *  @return an CyberOrg tuple matched with the specified tuple template.
     * 
     *  @throws TupleSpaceException 
     *              if this tuple space cannot find any CyberOrg tuple
     *              that are matched with the specified tuple template.
     */
    public CyberOrgTuple take(CyberOrgTuple p_ctTemplate)
	throws TupleSpaceException
    {
	return(getImpl(p_ctTemplate, true));
    }


    /**
     *  Reads all CyberOrg tuples matched with the specified tuple template,
     *      and then removes them.
     * 
     *  @param p_ctTemplate a tuple template to be used for matching with
     *                      CyberOrg tuples in this tuple space.
     * 
     *  @return CyberOrg tuples matched with the specified tuple template.
     * 
     *  @throws TupleSpaceException 
     *              if this tuple space cannot find any CyberOrg tuple
     *              that are matched with the specified tuple template.
     */
    public CyberOrgTuple[] takeAll(CyberOrgTuple p_ctTemplate)
	throws TupleSpaceException
    {
	return(getAllImpl(p_ctTemplate, true));
    }


    /**
     *  Removes CyberOrg tuples matched with the given tuple template,
     *      and then inserts an CyberOrg tuple in this tuple space.
     * 
     *  @param p_ctTemplate a tuple template to be used for matching with
     *                      CyberOrg tuples in this tuple space.
     *  @param p_ctTuple an CyberOrg tuple to be stored in this tuple space.
     * 
     *  @throws TupleSpaceException
     *              either if the CyberOrg tuple is invalid or
     *                     if the type of an element in the given CyberOrg tuple
     *                         is not matched with the type of the corresponding 
     *                         element in the given tuple template.
     */
    public void update(CyberOrgTuple p_ctTemplate, CyberOrgTuple p_ctTuple)
	throws TupleSpaceException
    {
    	if ( (p_ctTemplate == null) ||
    	     (p_ctTuple == null) ) {
	    throw new TupleSpaceException("Illegal Paramer - " +
	    		"Any argument of this method should not be null");
    	}
    	
	//
	//  check if the CyberOrg tuple is valid.
	//
	if (!isValidDataTuple(p_ctTuple)) {
	    throw new TupleSpaceException("Illegal Paramer - " +
	    		"Each element of an CyberOrg tuple should not be null");
	}

	//
	//  check if the types of elements of the given CyberOrg tuple are matched with
	//      the types of corresponding elements of the given tuple template.
	//
	if (!areTypeMatched(p_ctTemplate, p_ctTuple)) {
	    throw new TupleSpaceException("The type of an element in the given tuple template " +
	                                  "is not matched with " +
				          "that of the corresponding element in the given tuple");
	}

	//
	//  remove CyberOrg tuples matched with the given actor template.
	//
	try {
	    removeAll(p_ctTemplate);
	} catch (TupleSpaceException e) {
	}
        
	//
	//  add the given CyberOrg tuple.
	//
	m_llCyberOrgTuples.add(p_ctTuple);
    }
    

    /**
     *  Removes all CyberOrg tuples matched with the specified tuple template.
     * 
     *  @param p_ctTemplate a tuple template to be used for matching with
     *                      CyberOrg tuples in this tuple space.
     * 
     *  @throws TupleSpaceException 
     * 		    if this tuple space cannot find any CyberOrg tuple
     *              that are matched with the specified tuple template.
     */ 
    public void removeAll(CyberOrgTuple p_ctTemplate)
	throws TupleSpaceException
    {
	CyberOrgTuple[] anMatchedTuples = getMatchedTupleList(p_ctTemplate, true);

        if (anMatchedTuples.length > 0) {
	    for (int i=0; i<anMatchedTuples.length; i++) {
		m_llCyberOrgTuples.remove(anMatchedTuples[i]);
	    }
	} else {
            throw new TupleSpaceException("Cannot Find Any Tuple");
        }
    }


    /**
     *  Returns the CyberOrg in an CyberOrg tuple
     *      matched with the specified tuple template.
     * 
     *  @param p_ctTemplate a tuple template to be used for matching with
     *                      CyberOrg tuples in this tuple space.
     * 
     *  @return the CyberOrg in an CyberOrg tuple matched with the specified tuple template.
     * 
     *  @throws TupleSpaceException 
     *  	    if this tuple space cannot find any CyberOrg tuple
     *              that are matched with the specified tuple template.
     */
    public final CyberOrg search(CyberOrgTuple p_ctTemplate)
	throws TupleSpaceException
    {
	CyberOrgTuple[] anMatchedTuples = getMatchedTupleList(p_ctTemplate, false);

        if (anMatchedTuples.length > 0) {
	    Random rnd = new Random();
	    int iIdx = rnd.nextInt(anMatchedTuples.length);

            return anMatchedTuples[iIdx].getCyberOrg();
        } else {
            throw new TupleSpaceException("Cannot Find Any CyberOrg");
        }
    }
    

    /**
     *  Returns actor names in all actor tuples 
     *      matched with the specified tuple template.
     * 
     *  @param p_atTemplate a tuple template to be used for matching with
     *                      actor tuples in this tuple space.
     * 
     *  @return actor names in all actor tuples matched with the specified tuple template.
     * 
     *  @throws TupleSpaceException 
     *              if this tuple space cannot find any actor tuple 
     *              that are matched with the specified tuple template.
     */
    public final CyberOrg[] searchAll(CyberOrgTuple p_ctTemplate)
	throws TupleSpaceException
    {
	CyberOrgTuple[] anMatchedTuples = getMatchedTupleList(p_ctTemplate, false);
	LinkedList llCyberOrgs = new LinkedList();

        if (anMatchedTuples.length > 0) {
	    for (int i=0; i<anMatchedTuples.length; i++) {
	    	llCyberOrgs.add(anMatchedTuples[i].getCyberOrg());
	    }

//          return (ActorName[])llCyberOrgs.toArray();
	    CyberOrg anaCyberOrgs[] = new CyberOrg[llCyberOrgs.size()];
	    for (int i=0; i<llCyberOrgs.size(); i++) {
	    	anaCyberOrgs[i] = (CyberOrg)llCyberOrgs.get(i);
	    }
	    return anaCyberOrgs;
        } else {
            throw new TupleSpaceException("Cannot Find Any CyberOrg");
        }
    }
}
